//
//  UWGameBoard.m
//  Urban Words
//
//  Created by Tim Brandin on 2011-12-01.
//  Copyright (c) 2011 Sypreme. All rights reserved.
//

#import "UWGameBoard.h"
#import "BoardPrefs.h"

@interface UWGameBoard()
- (void)saveLetters;
@end

@implementation UWGameBoard

@synthesize delegate, game;
@synthesize shuffle, place, fail, success, turn;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        
        // enable tap to zoom
        [self setUserInteractionEnabled:YES];
        [self setMultipleTouchEnabled:YES];
        twoFingerTapIsPossible = YES;
        multipleTouches = NO;
        
        // add sounds
        
        shuffle = [self createSoundID:@"pokerchip09.wav"];
        place = [self createSoundID:@"pokerchip04-silent.wav"];
        fail = [self createSoundID:@"organic_nav_35.wav"];
        success = [self createSoundID:@"organic_nav_34.wav"];
        turn = [self createSoundID:@"congrats.wav"];
    }
    return self;
}

#pragma mark - words

/*
 * Adds words to board. 
 * Returns rectangle of area being modified
 */
- (CGRect)putWords:(PTPusherEvent *)result
{
    
    // set all old newbrick to oldbrick
    for (int i=0; i < BRICK_COUNT*BRICK_COUNT; i++) {
        bricks[i].oldtile = YES;
        
        if (bricks[i].newtile) {
            bricks[i].oldtile = YES;
            bricks[i].alpha = 1;
        }
        
        bricks[i].newtile = NO;
    }
    
    NSString *trigger = [result valueForKey:@"trigger"];
    
    BRICK_STATE state = NONE;
    
    if ([trigger isEqualToString:[[NSUserDefaults standardUserDefaults] valueForKey:@"Fid"]]) {
        state = PASS;
    } else {
        state = OPPONENT;
    }
    
    int minX = INT_MAX, maxX = INT_MIN, minY = INT_MAX, maxY = INT_MIN;
    
    NSArray *words = (NSArray *)[result valueForKey:@"words"];
    
    for(NSObject *word in words) {
        if ([word isKindOfClass:[NSDictionary class]]) {
            NSString *str = [word valueForKey:@"word"];
            int id = [((NSNumber *)[word valueForKey:@"id"]) intValue];
            int h = [((NSNumber *)[word valueForKey:@"h"]) intValue];
            
            int maxID = id + [str length]*(1 + 14*h);
            int size = (BRICK_SIZE + BRICK_MARGIN);
            
            minX = MIN(((int)(id / BRICK_COUNT)) * size + BOARD_MARGIN, minX);
            maxX = MAX(((int)(maxID / BRICK_COUNT)) * size + BOARD_MARGIN, maxX);
            
            minY = MIN((id % BRICK_COUNT) * size + BOARD_MARGIN, minY);
            maxY = MAX((maxID % BRICK_COUNT) * size + BOARD_MARGIN, maxY);

            [self putWord:str atPos:id atDirection:h withState:state];
        }
    }
    
    [self saveLetters];
   
    return CGRectMake(minX, minY, maxX - minX, maxY - minY);
}

- (void)putWord:(NSString *)word atPos:(int)id atDirection:(int)h withState:(BRICK_STATE)state
{
    for (int i=0; i < [word length]; i++) {
        int localID = id + i * (1 + 14*h);
        UWBrick *brick = bricks[localID];
        
        brick.state = state;// OPPONENT; //state;
        
        brick.newtile = YES;
        brick.oldtile = NO;
        
        [self setLetter:[word substringWithRange:NSMakeRange(i, 1)] atPos:localID];
    }
    
}

- (SystemSoundID)createSoundID:(NSString *)src
{
    NSString *path = [NSString stringWithFormat:@"%@/%@", [NSBundle mainBundle].resourcePath, src];
    
    NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
    
    SystemSoundID soundID;
    
    AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
    
    return soundID;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // cancel any pending handleSingleTap messages
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleSingleTap) object:nil];
    
    if ([[event touchesForView:self] count] > 1) {
        multipleTouches = YES;
    }
    if ([[event touchesForView:self] count] > 2) {
        twoFingerTapIsPossible = NO;
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    BOOL allTouchesEnded = ([touches count] == [[event touchesForView:self] count]);
    
    // first check for plain single/double tap, which is only possible if we haven't seen multiple touches.
    if (!multipleTouches) {
        UITouch *touch = [touches anyObject];
        tapLocation = [touch locationInView:self];
        
        if ([touch tapCount] == 1) {
            [self performSelector:@selector(handleSingleTap) withObject:nil afterDelay:DOUBLE_TAP_DELAY];
        } else if ([touch tapCount] == 2) {
            [self handleDoubleTap];
        }
    }
    
    // check for 2-finger tap if we've seen multiple touches and haven't yet ruled out that possibility
    else if (multipleTouches && twoFingerTapIsPossible) {
        
        // case 1: this is the end of both touches at once
        if ([touches count] == 2 && allTouchesEnded) {
            int i = 0;
            int tapCounts[2]; CGPoint tapLocations[2];
            for (UITouch *touch in touches) {
                tapCounts[i]    = [touch tapCount];
                tapLocations[i]  = [touch locationInView:self];
                i++;
            }
            if (tapCounts[0] == 1 && tapCounts[1] == 1) { // it's a two finger tap if they're both single taps
                tapLocation = midpointBetweenTouches(tapLocations[0], tapLocations[1]);
                [self handleTwoFingerTap];
            }
        }
        
        // case 2: this is the end of one touch, and the other hasn't ended yet
        else if ([touches count] == 1 && !allTouchesEnded) {
            UITouch *touch = [touches anyObject];
            if ([touch tapCount] == 1) {
                // if touch is a single tap, store its location so we can average it with the second touch location
                tapLocation = [touch locationInView:self];
            } else {
                twoFingerTapIsPossible = NO;
            }
        }
        
        // case 3: this is the end of the second of the two touches
        else if ([touches count] == 1 && allTouchesEnded) {
            UITouch *touch = [touches anyObject];
            if ([touch tapCount] == 1) {
                // if the last touch up is a single tap, this was a 2-finger tap
                tapLocation = midpointBetweenTouches(tapLocation, [touch locationInView:self]);
                [self handleTwoFingerTap];
            }
        }
    }
    
    // if all touches are up, reset to touch monitoring state
    if (allTouchesEnded) {
        twoFingerTapIsPossible = YES;
        multipleTouches = NO;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    twoFingerTapIsPossible = YES;
    multipleTouches = NO;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *tileView;
    UIView *returnView = [super hitTest:point withEvent:event];
    
    if ([delegate respondsToSelector:@selector(boardView:hitTest:withEvent:)]) {
        tileView = [delegate boardView:self hitTest:point withEvent:event];
    }
    
    if (tileView != nil) {
        returnView = tileView;
    }
    
    return returnView;
}

#pragma mark Private

- (void)handleSingleTap
{
    if ([delegate respondsToSelector:@selector(boardView:gotSingleTapAtPoint:)])
        [delegate boardView:self gotSingleTapAtPoint:tapLocation];
}

- (void)handleDoubleTap
{
    if ([delegate respondsToSelector:@selector(boardView:gotDoubleTapAtPoint:)])
        [delegate boardView:self gotDoubleTapAtPoint:tapLocation];
}

- (void)handleTwoFingerTap
{
    if ([delegate respondsToSelector:@selector(boardView:gotTwoFingerTapAtPoint:)])
        [delegate boardView:self gotTwoFingerTapAtPoint:tapLocation];
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    if (ctx == nil) {
        ctx = UIGraphicsGetCurrentContext();
    }
    
    CGContextTranslateCTM(ctx, 0.0, rect.size.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);
    
    // Drawing code
    if (game != nil) {
        
        // decompress board
        int j = 0;
        for(int i=0; i < [game.board length]; i++) {
            unichar c = [game.board characterAtIndex:i];
            int ci = c;
            if (ci > 97) {
                j += ci-97;
            }
            else {
                letters[j] = c;
                j++;
            }
        }
        
        int //startX = floorf( (rect.origin.x)/(BRICK_SIZE + BRICK_MARGIN) ),
            //startY = floorf( (rect.origin.y)/(BRICK_SIZE + BRICK_MARGIN) ),
            stopX = BRICK_COUNT,
            stopY = BRICK_COUNT;

        // print bricks
        for(int i=0; i < stopX; i++) {
            for(int j=0; j < stopY; j++) {
                int x = (BRICK_SIZE + BRICK_MARGIN) * i + BOARD_MARGIN,
                    y = (BRICK_SIZE + BRICK_MARGIN) * (BRICK_COUNT-1) - (BRICK_SIZE + BRICK_MARGIN) * j + BOARD_MARGIN;
                
                if (i == 7 && j == 7) {
                    [self paintStarBrick: (i * BRICK_COUNT + j) X:x Y:y Rect:rect];
                } else {
                    [self paintBrick: (i * BRICK_COUNT + j) X:x Y:y Rect:rect];
                }
            }
        }
    }
}

- (void)setLetter:(NSString *)letter atPos:(int)position 
{
    letters[position] = [letter characterAtIndex:0];  
}

- (void)setLetter:(NSString *)letter atPos:(int)position withState:(BRICK_STATE)state
{
    [self setLetter:letter atPos:position];
    bricks[position].state = state;
}

- (void)saveLetters
{
    NSLog(@"board: %@", game.board);
    NSMutableString *board = [[NSMutableString alloc] initWithString:@""];
    for (int i = 0, j = 0; i < BRICK_COUNT*BRICK_COUNT; i++) {
        if (letters[i]) {
            if (j > 0)
                [board appendString:[NSString stringWithFormat:@"%C", (j+97)]];
            [board appendString:[NSString stringWithFormat:@"%C", letters[i]]];
            j = 0;
        }
        else if (j == 24){
            [board appendString:@"z"];
            j = 0;
        } else {
            j++;
        }
    }
    game.board = board;
        NSLog(@"board: %@", game.board);
}

- (void)clearLetterAtPos:(int)position
{
    letters[position] = 0;
    bricks[position].state = NONE;
    bricks[position].alpha = 0;
}

- (void)paintBrick:(int)id X:(int)x Y:(int)y Rect:(CGRect)rect
{
    if (bricks[id] == nil && ctx != nil) {
        bricks[id] = [[[UWBrick alloc] initWithCGContextRef:ctx X:x Y:y] retain];
        [bricks[id] setType:MAX([game.boardSpecial characterAtIndex:id]-48, 0)];
    }
    
    // update brick with a letter if there is one
    if (letters[id]) {
        bricks[id].letter = [NSString stringWithFormat:@"%C", letters[id]];
        /*if (rand() % 10 > 6) {
            bricks[id].state = FAIL;
        }
        else if (rand() % 10 < 3) {
            bricks[id].state = MARK;
        }*/
    } 
    else {
        bricks[id].letter = nil;
    }
    
    [bricks[id] render:rect];
    
}

- (void)paintStarBrick:(int)id X:(int)x Y:(int)y Rect:(CGRect)rect
{
    if (bricks[id] == nil && ctx != nil) {
        bricks[id] = [[UWBrick alloc] initWithCGContextRef:ctx X:x Y:y];
        [bricks[id] setType:STAR];
    }
    
    // update brick with a letter if there is one
    if (letters[id]) {
        bricks[id].letter = [NSString stringWithFormat:@"%C", letters[id]];
        /*if (rand() % 10 > 6) {
         bricks[id].state = FAIL;
         }
         else if (rand() % 10 < 3) {
         bricks[id].state = MARK;
         }*/
    } 
    else {
        if (bricks[id].letter) {
            [bricks[id].letter release];
        }
        bricks[id].letter = nil;
    }
    
    [bricks[id] render:rect];
}

- (UWBrick *)getBrickAt:(int)pos {
    return bricks[pos];
}

- (void)dealloc
{
    // remove all data related to this class
    // bricks... etc
    [super dealloc];
}

@end

CGPoint midpointBetweenTouches(CGPoint a, CGPoint b) {
    CGFloat x = (a.x + b.x) / 2.0;
    CGFloat y = (a.y + b.y) / 2.0;
    return CGPointMake(x, y);
}
